
import { GroupCluster } from "../clusters/cluster";
import { GroupCarriers } from "./carriers";
import { ClusterHarvesters } from "../clusters/harvesters";
import { GroupUpgraders } from "./upgraders";
import { getCreepBodyCountCoeficient, getCreepCountCoeficient } from "../../../role/spawn";
import { GroupMaintainers } from "./maintainer";
import { errLog } from "../../../util/log";

export class GroupWorkers extends GroupCluster{
    constructor(spawnRoom=undefined){
        super(spawnRoom);
        if(spawnRoom!=undefined){
            this.init(spawnRoom);
        }
    }
    init(spawnRoom){
        this.harvesterGroupCluster=new ClusterHarvesters(spawnRoom);
        this.carrierGroup=new GroupCarriers(spawnRoom);
        this.maintainerGroup=new GroupMaintainers(spawnRoom);
        this.upgraderGroup=new GroupUpgraders(spawnRoom);
    }
    serialize(){
        return {
            super:super.serialize(), 
            harvesterGroup:this.harvesterGroupCluster.serialize(),
            carrierGroup:this.carrierGroup.serialize(),
            maintainerGroup:this.maintainerGroup.serialize(),
            upgraderGroup:this.upgraderGroup.serialize(),
        };
    }
    deserialize(obj){
        super.deserialize(obj.super);
        this.harvesterGroupCluster=new ClusterHarvesters().deserialize(obj.harvesterGroup);
        this.carrierGroup=new GroupCarriers().deserialize(obj.carrierGroup);
        this.maintainerGroup=new GroupMaintainers().deserialize(obj.maintainerGroup);
        this.upgraderGroup=new GroupUpgraders().deserialize(obj.upgraderGroup);
        return this;
    }
    get size(){
        return this.harvesterGroupCluster.size+
            this.maintainerGroup.size+
            this.carrierGroup.size+
            this.upgraderGroup.size;
    }
    getCarriersMaxSize(){
        return Math.ceil(this.harvesterGroupCluster.maxCount*this.getCarrierPerSource());
    }
    getCarrierPerSource(){
        return 0.34+(1-getCreepBodyCountCoeficient(this.spawnRoom))
    }
    get maxSize(){
        let ans=0;
        ans+=this.harvesterGroupCluster.maxSize;
        ans+=this.upgraderGroup.maxSize;
        ans+=this.maintainerGroup.maxSize;
        ans+=this.getCarriersMaxSize();
        return ans;
    }
    spawn(){
        if(this.harvesterGroupCluster.size < 2){
            const ret = this.harvesterGroupCluster.spawn();
            return ret;
        }
        if(this.upgraderGroup.size === 0){
            return this.upgraderGroup.spawn();
        }
        if(this.carrierGroup.size/this.getCarriersMaxSize()<this.harvesterGroupCluster.size/this.harvesterGroupCluster.maxSize){
            return this.carrierGroup.spawn();
        }
        if(this.maintainerGroup.size/this.maintainerGroup.maxSize<this.carrierGroup.size/this.getCarriersMaxSize() && getCreepCountCoeficient(this.spawnRoom)>0.98){
            return this.maintainerGroup.spawn();
        }
        if(this.harvesterGroupCluster.size<this.harvesterGroupCluster.maxSize){
            return this.harvesterGroupCluster.spawn();
        }

        if(this.carrierGroup.size/this.getCarriersMaxSize()>this.upgraderGroup.size/this.upgraderGroup.maxSize){
            return this.upgraderGroup.spawn();
        }

        if(this.getCarriersMaxSize()<this.carrierGroup.size){
            return this.carrierGroup.spawn();
        }

        if(this.upgraderGroup.size<this.upgraderGroup.maxSize){
            return this.upgraderGroup.spawn();
        }

        if(this.maintainerGroup.size<this.maintainerGroup.maxSize){
            return this.maintainerGroup.spawn();
        }
        
        return ERR_FULL;
    }
    run(){
        let forceStay = this.carrierGroup.size > 0 
            || this.carrierGroup.creeps.some((creep)=>!creep.spawning);

        try{
            this.upgraderGroup.run(forceStay);
        }catch(e){
            errLog(e)
        }
        try{
            this.carrierGroup.run();
        }catch(e){
            errLog(e)
        }
        try{
            this.harvesterGroupCluster.run(forceStay);
        }catch(e){
            errLog(e)
        }
        try{
            this.maintainerGroup.run();
        }catch(e){
            errLog(e)
        }

        return OK;
    }
}